Skip to content

Expose adaptive context APIs for Swift LLM#512

Open
shubhamsinnh wants to merge 9 commits into
RunanywhereAI:mainfrom
shubhamsinnh:issue-500-adaptive-context
Open

Expose adaptive context APIs for Swift LLM#512
shubhamsinnh wants to merge 9 commits into
RunanywhereAI:mainfrom
shubhamsinnh:issue-500-adaptive-context

Conversation

@shubhamsinnh

@shubhamsinnh shubhamsinnh commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Description

Exposes adaptive-context LLM operations through the component and lifecycle-owned C ABI, then adds matching Swift public APIs so callers can reuse the model loaded through the existing RunAnywhere.loadModel flow.

Changes include:

  • component wrappers for inject, append, generate-from-context, and clear
  • lifecycle-owned C ABI helpers for the Swift/public path
  • Swift RunAnywhere.injectSystemPrompt, appendContext, generateFromContext, and clearContext
  • matching vendored headers and Apple symbol exports
  • review fixes preserving component default options and native backend error details

The public Swift path remains lifecycle-owned, avoiding a second model/service handle and its associated memory cost.

Fixes #500

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Refactoring

Testing

  • Lint passes locally
  • Added/updated tests for changes

Validation performed:

  • git diff --check
  • focused declaration/definition/export symbol audit for all eight new C symbols
  • verified llama.cpp and MetalRT generate-from-context paths continue from existing context/cache
  • fork CI run: https://github.com/shubhamsinnh/runanywhere-sdks/actions/runs/28582734898
    • swift-spm: passed
    • ios-device: passed
    • macos-debug: passed
    • Linux, Android, WASM, and validation lanes: passed
  • macos-release failed before this PR's code while compiling committed generated protobuf headers against Homebrew protobuf 35.1; macos-debug passed in the same matrix
  • freshness audit against current main:
    • lifecycle/public adaptive-context symbols remain absent from main
    • underlying service operations remain present
    • synthetic three-way merge reports no conflicts
    • GitHub reports the PR mergeable

Platform-Specific Testing (check all that apply)

Swift SDK / iOS Sample:

  • Tested on iPhone (Simulator or Device)
  • Tested on iPad / Tablet
  • Tested on Mac (macOS target)

Kotlin SDK / Android Sample:

  • Tested on Android Phone (Emulator or Device)
  • Tested on Android Tablet

Flutter SDK / Flutter Sample:

  • Tested on iOS
  • Tested on Android

React Native SDK / React Native Sample:

  • Tested on iOS
  • Tested on Android

Playground:

  • Tested on target platform
  • Verified no regressions in existing Playground projects

Web SDK / Web Sample:

  • Tested in Chrome (Desktop)
  • Tested in Firefox
  • Tested in Safari
  • WASM backends load (LlamaCpp + ONNX)
  • OPFS storage persistence verified (survives page refresh)
  • Settings persistence verified (localStorage)

Labels

SDKs:

  • Swift SDK
  • Kotlin SDK
  • Flutter SDK
  • React Native SDK
  • Web SDK
  • Commons

Sample Apps:

  • iOS Sample
  • Android Sample
  • Flutter Sample
  • React Native Sample
  • Web Sample

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Documentation updated (public APIs and C ABI contracts include documentation)

Screenshots

Not applicable; this PR adds SDK APIs without changing UI.

Summary by CodeRabbit

  • New Features
    • Added an adaptive-context workflow for LLM text generation: inject a system prompt (clears KV/cache), append additional context incrementally, generate from the accumulated context, and clear adaptive context.
    • Exposed the workflow through component APIs and lifecycle-managed/protobuf entry points, plus Swift helpers (injectSystemPrompt, appendContext, generateFromContext, clearContext).
  • Bug Fixes
    • Improved consistent “not supported/not available” behavior when adaptive-context operations aren’t available, including clearer handling when no model is loaded.
  • Documentation
    • Updated LLM SDK headers to document the new adaptive-context APIs and their support expectations.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds adaptive-context APIs across the C, C++, and Swift layers, with new component wrappers, lifecycle/proto entry points, symbol exports, bridge methods, and public RunAnywhere helpers.

Changes

LLM Adaptive Context API

Layer / File(s) Summary
C API contracts
sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/rac_llm_component.h, sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/rac_llm_service.h, sdk/runanywhere-commons/include/rac/features/llm/rac_llm_component.h, sdk/runanywhere-commons/include/rac/features/llm/rac_llm_service.h
Declares component-level adaptive context functions and lifecycle/proto adaptive context functions in both header trees.
C++ component and proto implementation
sdk/runanywhere-commons/src/features/llm/llm_module.cpp
Adds component wrappers plus lifecycle/proto entry points for adaptive context handling, including request parsing and protobuf result serialization.
Symbol exports
sdk/runanywhere-commons/exports/RACommons.exports
Adds the new adaptive context symbols to the exported symbols list.
Swift bridge
sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Bridge/Extensions/CppBridge+LLM.swift
Adds the native ABI wrapper, CppBridge.LLM methods, and shared native status validation.
Public RunAnywhere API
sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/LLM/RunAnywhere+TextGeneration.swift
Exposes four static RunAnywhere methods that forward to the bridge after initialization and service readiness checks.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Related issue: #500
Suggested labels: ios-sdk
Suggested reviewers: shubhammalhotra28

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: exposing adaptive-context APIs for Swift LLM.
Description check ✅ Passed The description matches the template and covers the change summary, type, testing, labels, checklist, and screenshots.
Linked Issues check ✅ Passed The PR adds the missing component wrappers and Swift-facing APIs requested by #500 while preserving the existing adaptive-context flow.
Out of Scope Changes check ✅ Passed The added lifecycle-owned C ABI and Swift bridge APIs are part of the stated objective, with no unrelated changes evident.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 369d02c. Configure here.

Comment thread sdk/runanywhere-commons/src/features/llm/llm_module.cpp Outdated
@shubhamsinnh

Copy link
Copy Markdown
Contributor Author

Could a maintainer please approve the GitHub Actions run for this fork PR when you get a chance? I’m contributing from a Windows environment, so I can’t run the macOS/iOS Swift checks locally. I’ve included the local static checks I was able to run in the PR description.

@shubhamsinnh shubhamsinnh marked this pull request as ready for review June 27, 2026 17:28

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Bridge/Extensions/CppBridge`+LLM.swift:
- Around line 145-152: The error handling in throwIfFailed currently converts
all non-success statuses into a generic SDKException and drops the native
backend detail. Update CppBridge+LLM.throwIfFailed to include
rac_error_message(status) in the thrown message, especially when status is
RAC_ERROR_NOT_SUPPORTED or RAC_ERROR_FEATURE_NOT_AVAILABLE, so callers can
distinguish unsupported-backend failures from other processing errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 357d08be-b462-415a-9b02-74bd7babe36e

📥 Commits

Reviewing files that changed from the base of the PR and between c272a1f and 369d02c.

📒 Files selected for processing (8)
  • sdk/runanywhere-commons/exports/RACommons.exports
  • sdk/runanywhere-commons/include/rac/features/llm/rac_llm_component.h
  • sdk/runanywhere-commons/include/rac/features/llm/rac_llm_service.h
  • sdk/runanywhere-commons/src/features/llm/llm_module.cpp
  • sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/rac_llm_component.h
  • sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/rac_llm_service.h
  • sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Bridge/Extensions/CppBridge+LLM.swift
  • sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/LLM/RunAnywhere+TextGeneration.swift

@shubhamsinnh

Copy link
Copy Markdown
Contributor Author

Validation update after addressing the review feedback:

The only failed lane was macos-release. Its log fails while compiling committed generated protobuf headers against Homebrew protobuf 35.1 (incompatible version of Protobuf C++ headers/runtime), before reaching the adaptive-context changes. macos-debug passed in the same matrix, so this appears to be baseline/toolchain drift unrelated to this PR.

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
sdk/runanywhere-commons/src/features/llm/llm_module.cpp (1)

2153-2194: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider consolidating the near-identical lifecycle wrapper boilerplate.

rac_llm_inject_system_prompt_lifecycle, rac_llm_append_context_lifecycle, and rac_llm_clear_context_lifecycle all repeat the same shape: validate → #if !RAC_HAVE_PROTOBUF guard → acquire_lifecycle_llm → ternary dispatch on a vtable op → release_lifecycle_llm → return. A small helper (e.g., templated on the vtable member pointer, or a lambda-based wrapper) would collapse these into a few lines and reduce future copy/paste risk when more adaptive-context ops are added.

As per coding guidelines, "Focus on SIMPLICITY and follow Clean SOLID principles when writing code with emphasis on reusability, clean architecture style, and clear separation of concerns" for sdk/runanywhere-commons/**/*.{cpp,h,hpp,c}.

♻️ Illustrative consolidation sketch
+namespace {
+template <typename Op, typename... Args>
+rac_result_t call_lifecycle_op(Op op, Args&&... args) {
+#if !defined(RAC_HAVE_PROTOBUF)
+    return RAC_ERROR_FEATURE_NOT_AVAILABLE;
+#else
+    rac::llm::LifecycleLlmRef ref;
+    rac_result_t rc = rac::llm::acquire_lifecycle_llm(&ref);
+    if (rc != RAC_SUCCESS) return rc;
+    rc = (ref.ops && (ref.ops->*op)) ? (ref.ops->*op)(ref.impl, std::forward<Args>(args)...)
+                                     : RAC_ERROR_NOT_SUPPORTED;
+    rac::llm::release_lifecycle_llm(&ref);
+    return rc;
+#endif
+}
+}  // namespace
+
 rac_result_t rac_llm_inject_system_prompt_lifecycle(const char* prompt) {
-    if (!prompt) {
-        return RAC_ERROR_INVALID_ARGUMENT;
-    }
-#if !defined(RAC_HAVE_PROTOBUF)
-    return RAC_ERROR_FEATURE_NOT_AVAILABLE;
-#else
-    rac::llm::LifecycleLlmRef ref;
-    rac_result_t rc = rac::llm::acquire_lifecycle_llm(&ref);
-    if (rc != RAC_SUCCESS) {
-        return rc;
-    }
-
-    rc = (ref.ops && ref.ops->inject_system_prompt)
-             ? ref.ops->inject_system_prompt(ref.impl, prompt)
-             : RAC_ERROR_NOT_SUPPORTED;
-    rac::llm::release_lifecycle_llm(&ref);
-    return rc;
-#endif
+    if (!prompt) return RAC_ERROR_INVALID_ARGUMENT;
+    return call_lifecycle_op(&rac_llm_ops_t::inject_system_prompt, prompt);
 }

Also applies to: 2282-2298

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/runanywhere-commons/src/features/llm/llm_module.cpp` around lines 2153 -
2194, The lifecycle adaptive-context wrappers are duplicating the same
validate/acquire/dispatch/release pattern across
rac_llm_inject_system_prompt_lifecycle, rac_llm_append_context_lifecycle, and
rac_llm_clear_context_lifecycle. Refactor this into a small shared helper inside
llm_module.cpp, ideally one that takes the relevant vtable op (or a lambda) and
handles the RAC_HAVE_PROTOBUF guard, rac::llm::acquire_lifecycle_llm, null-op
fallback to RAC_ERROR_NOT_SUPPORTED, and rac::llm::release_lifecycle_llm
consistently. Keep the individual public wrappers as thin calls into that helper
so future adaptive-context lifecycle ops can be added without copy/paste.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@sdk/runanywhere-commons/src/features/llm/llm_module.cpp`:
- Around line 2153-2194: The lifecycle adaptive-context wrappers are duplicating
the same validate/acquire/dispatch/release pattern across
rac_llm_inject_system_prompt_lifecycle, rac_llm_append_context_lifecycle, and
rac_llm_clear_context_lifecycle. Refactor this into a small shared helper inside
llm_module.cpp, ideally one that takes the relevant vtable op (or a lambda) and
handles the RAC_HAVE_PROTOBUF guard, rac::llm::acquire_lifecycle_llm, null-op
fallback to RAC_ERROR_NOT_SUPPORTED, and rac::llm::release_lifecycle_llm
consistently. Keep the individual public wrappers as thin calls into that helper
so future adaptive-context lifecycle ops can be added without copy/paste.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bac05259-0d09-4190-97f8-fdea89942a8a

📥 Commits

Reviewing files that changed from the base of the PR and between c272a1f and ad51147.

📒 Files selected for processing (8)
  • sdk/runanywhere-commons/exports/RACommons.exports
  • sdk/runanywhere-commons/include/rac/features/llm/rac_llm_component.h
  • sdk/runanywhere-commons/include/rac/features/llm/rac_llm_service.h
  • sdk/runanywhere-commons/src/features/llm/llm_module.cpp
  • sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/rac_llm_component.h
  • sdk/runanywhere-swift/Sources/RunAnywhere/CRACommons/include/rac_llm_service.h
  • sdk/runanywhere-swift/Sources/RunAnywhere/Foundation/Bridge/Extensions/CppBridge+LLM.swift
  • sdk/runanywhere-swift/Sources/RunAnywhere/Public/Extensions/LLM/RunAnywhere+TextGeneration.swift

Copy link
Copy Markdown
Contributor Author

@coderabbitai The full review still reports 52.17% docstring coverage after commit ad51147 documented the eight new C++ adaptive-context definitions and the Swift native-status helper. Please identify the exact functions you still count as undocumented so we can address only concrete gaps.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
REPO="RunanywhereAI/runanywhere-sdks"
PR=512

# Get PR head ref info
gh pr view $PR --repo $REPO --json headRefName,headRepositoryOwner,headRepository -q '.'

# Fetch the branch to inspect files
gh pr diff $PR --repo $REPO > /tmp/pr512.diff
wc -l /tmp/pr512.diff

Length of output: 699


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Check for doc comments preceding the new functions in the diff
grep -n "rac_llm_component_inject_system_prompt\|rac_llm_component_append_context\|rac_llm_component_generate_from_context\|rac_llm_component_clear_context\|rac_llm_inject_system_prompt_lifecycle\|rac_llm_append_context_lifecycle\|rac_llm_generate_from_context_proto\|rac_llm_clear_context_lifecycle\|injectSystemPrompt\|appendContext\|generateFromContext\|clearContext\|throwIfFailed" -B5 /tmp/pr512.diff | head -400

Length of output: 869


🏁 Script executed:

#!/bin/bash
set -euo pipefail
REPO="RunanywhereAI/runanywhere-sdks"
PR=512

gh pr diff $PR --repo $REPO > /tmp/pr512.diff
wc -l /tmp/pr512.diff
echo "---- llm_module.cpp new functions context ----"
grep -n "^+.*rac_llm_component_inject_system_prompt\|^+.*rac_llm_component_append_context\|^+.*rac_llm_component_generate_from_context\|^+.*rac_llm_component_clear_context\|^+.*rac_llm_inject_system_prompt_lifecycle\|^+.*rac_llm_append_context_lifecycle\|^+.*rac_llm_generate_from_context_proto\|^+.*rac_llm_clear_context_lifecycle" /tmp/pr512.diff

echo "---- Swift new methods context ----"
grep -n "^+.*func injectSystemPrompt\|^+.*func appendContext\|^+.*func generateFromContext\|^+.*func clearContext\|^+.*func throwIfFailed" /tmp/pr512.diff

Length of output: 4206


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Inspect doc comments directly above each function definition in the diff
sed -n '160,260p' /tmp/pr512.diff
echo "======="
sed -n '380,430p' /tmp/pr512.diff
echo "======="
sed -n '555,650p' /tmp/pr512.diff

Length of output: 10603


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '260,310p' /tmp/pr512.diff
echo "===RunAnywhere+TextGeneration rest==="
sed -n '640,690p' /tmp/pr512.diff

Length of output: 4058


All eight new C++ adaptive-context definitions and the four Swift native-status/public methods I can see in this diff do carry doc comments (/** ... */ or ///), so I can't reproduce an undocumented gap among the new functions listed in the PR summary from this diff alone. That 52.17% figure is most likely a repo-wide docstring-coverage metric (e.g., from a tool configured against the whole codebase or the whole file), not a per-PR-diff score — so it can include long-standing pre-existing functions in the same files (e.g., rac_llm_component.h, rac_llm_service.h, llm_module.cpp) that were never documented, unrelated to this PR's adaptive-context additions.

A few things worth verifying on your end:

  1. Check the specific review comment/report from the docstring-coverage check for the exact file(s) and line numbers it flags — that will list the precise "undocumented" symbols. If the tool is a repo-level scan rather than diff-scoped, it will surface pre-existing gaps rather than anything from your new code.
  2. Confirm which files the 52.17% is computed over — if it's the whole llm_module.cpp/rac_llm_component.h/rac_llm_service.h, older/unrelated functions in those files could be dragging the percentage down even though your eight new functions and the Swift helper are documented.

If you can point me to the exact CodeRabbit review comment/report containing that 52.17% figure (or its comment ID/permalink), I can cross-reference it directly against the current diff and give you a concrete list of symbols it's still counting as undocumented, rather than guessing at the source of the metric.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@shubhamsinnh shubhamsinnh force-pushed the issue-500-adaptive-context branch from ad51147 to 2ba875f Compare July 5, 2026 09:27
@shubhamsinnh

shubhamsinnh commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Hi @shubhammalhotra28 , this one's ready for review. All CI checks passing, feedback addressed.
Happy to make any changes you'd like.
Thanks!

@Siddhesh2377

Copy link
Copy Markdown
Collaborator

Hey bro @shubhamsinnh
I think we have some merge conflicts here, please check them once fixed will merge it
Thanks :)

@shubhamsinnh

Copy link
Copy Markdown
Contributor Author

Hey bro @shubhamsinnh I think we have some merge conflicts here, please check them once fixed will merge it Thanks :)

Hi @Siddhesh2377 thanks for the nudge, getting this checked.

@shubhamsinnh

Copy link
Copy Markdown
Contributor Author

Hey bro @shubhamsinnh I think we have some merge conflicts here, please check them once fixed will merge it Thanks :)

Hi @Siddhesh2377 thanks for the nudge, getting this checked.

@Siddhesh2377 merge conflict resolved, it should be clean now.
Happy to make any changes if needed!!

@shubhamsinnh

Copy link
Copy Markdown
Contributor Author

Hi @shubhammalhotra28 @Siddhesh2377 — following up here.

The earlier feedback/conflict should be resolved now. Please let me know if you want any changes from my side.

@shubhamsinnh shubhamsinnh force-pushed the issue-500-adaptive-context branch from 632dda5 to e4535bc Compare July 13, 2026 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(LLM): expose adaptive-context APIs through component layer wrappers

2 participants